//
//  NSArray+THHook.m
//  MengLiao
//
//  Created by xiuxin on 2022/7/14.
//  Copyright © 2022 BaseBusiness. All rights reserved.
//
//  from https://github.com/chenfanfang/AvoidCrash

#import "NSArray+THHook.h"
#import "THDeBugTool.h"
#import "THCrashManager.h"
@implementation NSArray (THHook)

+ (void)load{
#ifdef DEBUG
    return;
#endif
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        Class __NSArray = NSClassFromString(@"NSArray");
        Class __NSArrayI = NSClassFromString(@"__NSArrayI");
        Class __NSSingleObjectArrayI = NSClassFromString(@"__NSSingleObjectArrayI");
        Class __NSArray0 = NSClassFromString(@"__NSArray0");
        Class __NSPlaceholderArray = NSClassFromString(@"__NSPlaceholderArray");
        
        ExchangeImplementationsInTwoClasses(__NSPlaceholderArray,@selector(initWithObjects:count:),
                                                  [NSArray class], @selector(avoid_initWithObjects:count:));
        ExchangeImplementationsInTwoClasses([NSArray class],@selector(arrayWithObjects:count:),
                                            [NSArray class], @selector(avoidCrashArrayWithObjects:count:));
        ExchangeImplementationsInTwoClasses(__NSArray, @selector(objectsAtIndexes:),
                                            [NSArray class],@selector(avoidCrashObjectsAtIndexes:));
        ExchangeImplementationsInTwoClasses(__NSArrayI,@selector(objectAtIndex:),
                                            [NSArray class], @selector(__NSArrayIAvoidCrashObjectAtIndex:));
        ExchangeImplementationsInTwoClasses(__NSSingleObjectArrayI, @selector(objectAtIndex:),
                                            [NSArray class], @selector(__NSSingleObjectArrayIAvoidCrashObjectAtIndex:));
        ExchangeImplementationsInTwoClasses(__NSArray0, @selector(objectAtIndex:),
                                            [NSArray class],@selector(__NSArray0AvoidCrashObjectAtIndex:));
        
        ExchangeImplementationsInTwoClasses(__NSArray,@selector(getObjects:range:),
                                            [NSArray class],@selector(NSArrayAvoidCrashGetObjects:range:));
        ExchangeImplementationsInTwoClasses(__NSSingleObjectArrayI,@selector(getObjects:range:),
                                            [NSArray class],@selector(__NSSingleObjectArrayIAvoidCrashGetObjects:range:));
        ExchangeImplementationsInTwoClasses(__NSArrayI, @selector(getObjects:range:),
                                            [NSArray class],@selector(__NSArrayIAvoidCrashGetObjects:range:));
        if ([[UIDevice currentDevice].systemVersion floatValue] >= 11.0){
            ExchangeImplementationsInTwoClasses(__NSArrayI, @selector(objectAtIndexedSubscript:),
                                                [NSArray class],@selector(__NSArrayIAvoidCrashObjectAtIndexedSubscript:));
        }
    });
}
- (instancetype)avoid_initWithObjects:(id  _Nonnull const [])objects count:(NSUInteger)cnt{
    id safeObjects[cnt];
    NSUInteger j = 0;
    for (NSUInteger i = 0; i < cnt; i++) {
        id obj = objects[i];
        if (!obj) {
#ifdef DEBUG
        NSString *errorDes = [NSString stringWithFormat:@"__NSPlaceholderArray (THHook) - 不合法的objects\n%@",[NSThread callStackSymbols]];
        NSLog(@"%@",errorDes);
#else
       NSString *errorDes = [NSString stringWithFormat:@"__NSPlaceholderArray (THHook)- objects\n%@",[NSThread callStackSymbols]];
       NSError *error = [NSError errorWithDomain:@"huanque" code:10003 userInfo:@{NSLocalizedDescriptionKey:errorDes}];
       [[THCrashManager shareInstance] reportError:error];
#endif
        continue;
        }
        safeObjects[j] = obj;
        j++;
    }
    return [self avoid_initWithObjects:safeObjects count:j];
}
+ (instancetype)avoidCrashArrayWithObjects:(const id  _Nonnull __unsafe_unretained *)objects count:(NSUInteger)cnt {
    id instance = nil;
    @try {
        instance = [self avoidCrashArrayWithObjects:objects count:cnt];
    }
    @catch (NSException *exception) {
        [[THCrashManager shareInstance] reportExp:exception];
        //以下是对错误数据的处理，把为nil的数据去掉,然后初始化数组
        NSInteger newObjsIndex = 0;
        id  _Nonnull __unsafe_unretained newObjects[cnt];
        for (int i = 0; i < cnt; i++) {
            if (objects[i] != nil) {
                newObjects[newObjsIndex] = objects[i];
                newObjsIndex++;
            }
        }
        instance = [self avoidCrashArrayWithObjects:newObjects count:newObjsIndex];
    }
    @finally {
        return instance;
    }
}
#pragma mark - objectAtIndexedSubscript:
- (id)__NSArrayIAvoidCrashObjectAtIndexedSubscript:(NSUInteger)idx {
    id object = nil;
    @try {
        object = [self __NSArrayIAvoidCrashObjectAtIndexedSubscript:idx];
    }@catch (NSException *exception) {
        [[THCrashManager shareInstance] reportExp:exception];
    }@finally {
        return object;
    }
}
#pragma mark - objectsAtIndexes:
- (NSArray *)avoidCrashObjectsAtIndexes:(NSIndexSet *)indexes {
    NSArray *returnArray = nil;
    @try {
        returnArray = [self avoidCrashObjectsAtIndexes:indexes];
    } @catch (NSException *exception) {
         [[THCrashManager shareInstance] reportExp:exception];
    } @finally {
        return returnArray;
    }
}
#pragma mark - objectAtIndex:
- (id)__NSArrayIAvoidCrashObjectAtIndex:(NSUInteger)index {
    id object = nil;
    @try {
        object = [self __NSArrayIAvoidCrashObjectAtIndex:index];
    }@catch (NSException *exception) {
        [[THCrashManager shareInstance] reportExp:exception];
    }
    @finally {
        return object;
    }
}
- (id)__NSSingleObjectArrayIAvoidCrashObjectAtIndex:(NSUInteger)index {
    id object = nil;
    @try {
        object = [self __NSSingleObjectArrayIAvoidCrashObjectAtIndex:index];
    }@catch (NSException *exception) {
      [[THCrashManager shareInstance] reportExp:exception];
    }@finally {
        return object;
    }
}
- (id)__NSArray0AvoidCrashObjectAtIndex:(NSUInteger)index {
    id object = nil;
    @try {
        object = [self __NSArray0AvoidCrashObjectAtIndex:index];
    }@catch (NSException *exception) {
         [[THCrashManager shareInstance] reportExp:exception];
    }@finally {
        return object;
    }
}
#pragma mark - getObjects:range:
- (void)NSArrayAvoidCrashGetObjects:(__unsafe_unretained id  _Nonnull *)objects range:(NSRange)range {
    @try {
        [self NSArrayAvoidCrashGetObjects:objects range:range];
    } @catch (NSException *exception) {
       [[THCrashManager shareInstance] reportExp:exception];
    } @finally {
        
    }
}
- (void)__NSSingleObjectArrayIAvoidCrashGetObjects:(__unsafe_unretained id  _Nonnull *)objects range:(NSRange)range {
    @try {
        [self __NSSingleObjectArrayIAvoidCrashGetObjects:objects range:range];
    } @catch (NSException *exception) {
         [[THCrashManager shareInstance] reportExp:exception];
    } @finally {
        
    }
}
- (void)__NSArrayIAvoidCrashGetObjects:(__unsafe_unretained id  _Nonnull *)objects range:(NSRange)range {
    @try {
        [self __NSArrayIAvoidCrashGetObjects:objects range:range];
    } @catch (NSException *exception) {
        [[THCrashManager shareInstance] reportExp:exception];
    } @finally {
    }
}
@end
